<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=2">
<meta name="theme-color" content="#222">
<meta name="generator" content="Hexo 5.2.0">
  <link rel="apple-touch-icon" sizes="180x180" href="/song311/images/apple-touch-icon-next.png">
  <link rel="icon" type="image/png" sizes="32x32" href="/song311/images/favicon-32x32-next.png">
  <link rel="icon" type="image/png" sizes="16x16" href="/song311/images/favicon-16x16-next.png">
  <link rel="mask-icon" href="/song311/images/logo.svg" color="#222">

<link rel="stylesheet" href="/song311/css/main.css">


<link rel="stylesheet" href="/song311/lib/font-awesome/css/all.min.css">

<script id="hexo-configurations">
    var NexT = window.NexT || {};
    var CONFIG = {"hostname":"hdu_university.gitee.io","root":"/song311/","scheme":"Gemini","version":"7.8.0","exturl":false,"sidebar":{"position":"left","display":"post","padding":18,"offset":12,"onmobile":false},"copycode":{"enable":false,"show_result":false,"style":null},"back2top":{"enable":true,"sidebar":true,"scrollpercent":true},"bookmark":{"enable":false,"color":"#222","save":"auto"},"fancybox":false,"mediumzoom":false,"lazyload":false,"pangu":false,"comments":{"style":"tabs","active":null,"storage":true,"lazyload":false,"nav":null},"algolia":{"hits":{"per_page":10},"labels":{"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}},"localsearch":{"enable":true,"trigger":"auto","top_n_per_article":1,"unescape":false,"preload":false},"motion":{"enable":true,"async":false,"transition":{"post_block":"fadeIn","post_header":"slideDownIn","post_body":"slideDownIn","coll_header":"slideLeftIn","sidebar":"slideUpIn"}},"path":"search.xml"};
  </script>

  <meta name="description" content="1. 工厂模式 简单工厂模式 工厂方法模式 抽象工厂模式">
<meta property="og:type" content="article">
<meta property="og:title" content="设计模式">
<meta property="og:url" content="http://hdu_university.gitee.io/song311/2020/09/22/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/index.html">
<meta property="og:site_name" content="Song&#39;s blog">
<meta property="og:description" content="1. 工厂模式 简单工厂模式 工厂方法模式 抽象工厂模式">
<meta property="og:locale" content="zh_CN">
<meta property="og:image" content="http://hdu_university.gitee.io/song311/D:/Typora/photo/image-20200908153800601.png">
<meta property="og:image" content="http://hdu_university.gitee.io/song311/D:/Typora/photo/image-20200908154951744.png">
<meta property="article:published_time" content="2020-09-21T16:00:00.000Z">
<meta property="article:modified_time" content="2020-09-22T01:12:14.175Z">
<meta property="article:author" content="asong">
<meta property="article:tag" content="设计模式">
<meta name="twitter:card" content="summary">
<meta name="twitter:image" content="http://hdu_university.gitee.io/song311/D:/Typora/photo/image-20200908153800601.png">

<link rel="canonical" href="http://hdu_university.gitee.io/song311/2020/09/22/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">


<script id="page-configurations">
  // https://hexo.io/docs/variables.html
  CONFIG.page = {
    sidebar: "",
    isHome : false,
    isPost : true,
    lang   : 'zh-CN'
  };
</script>

  <title>设计模式 | Song's blog</title>
  






  <noscript>
  <style>
  .use-motion .brand,
  .use-motion .menu-item,
  .sidebar-inner,
  .use-motion .post-block,
  .use-motion .pagination,
  .use-motion .comments,
  .use-motion .post-header,
  .use-motion .post-body,
  .use-motion .collection-header { opacity: initial; }

  .use-motion .site-title,
  .use-motion .site-subtitle {
    opacity: initial;
    top: initial;
  }

  .use-motion .logo-line-before i { left: initial; }
  .use-motion .logo-line-after i { right: initial; }
  </style>
</noscript>

</head>

<body itemscope itemtype="http://schema.org/WebPage">
  <div class="container use-motion">
    <div class="headband"></div>

    <header class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-container">
  <div class="site-nav-toggle">
    <div class="toggle" aria-label="切换导航栏">
      <span class="toggle-line toggle-line-first"></span>
      <span class="toggle-line toggle-line-middle"></span>
      <span class="toggle-line toggle-line-last"></span>
    </div>
  </div>

  <div class="site-meta">

    <a href="/song311/" class="brand" rel="start">
      <span class="logo-line-before"><i></i></span>
      <h1 class="site-title">Song's blog</h1>
      <span class="logo-line-after"><i></i></span>
    </a>
      <p class="site-subtitle" itemprop="description">Try Harder</p>
  </div>

  <div class="site-nav-right">
    <div class="toggle popup-trigger">
        <i class="fa fa-search fa-fw fa-lg"></i>
    </div>
  </div>
</div>




<nav class="site-nav">
  <ul id="menu" class="main-menu menu">
        <li class="menu-item menu-item-home">

    <a href="/song311/" rel="section"><i class="fa fa-home fa-fw"></i>首页</a>

  </li>
        <li class="menu-item menu-item-tags">

    <a href="/song311/tags/" rel="section"><i class="fa fa-tags fa-fw"></i>标签</a>

  </li>
        <li class="menu-item menu-item-categories">

    <a href="/song311/categories/" rel="section"><i class="fa fa-th fa-fw"></i>分类</a>

  </li>
        <li class="menu-item menu-item-archives">

    <a href="/song311/archives/" rel="section"><i class="fa fa-archive fa-fw"></i>归档</a>

  </li>
      <li class="menu-item menu-item-search">
        <a role="button" class="popup-trigger"><i class="fa fa-search fa-fw"></i>搜索
        </a>
      </li>
  </ul>
</nav>



  <div class="search-pop-overlay">
    <div class="popup search-popup">
        <div class="search-header">
  <span class="search-icon">
    <i class="fa fa-search"></i>
  </span>
  <div class="search-input-container">
    <input autocomplete="off" autocapitalize="off"
           placeholder="搜索..." spellcheck="false"
           type="search" class="search-input">
  </div>
  <span class="popup-btn-close">
    <i class="fa fa-times-circle"></i>
  </span>
</div>
<div id="search-result">
  <div id="no-result">
    <i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>
  </div>
</div>

    </div>
  </div>

</div>
    </header>

    


    <main class="main">
      <div class="main-inner">
        <div class="content-wrap">
          

          <div class="content post posts-expand">
            

    
  
  
  <article itemscope itemtype="http://schema.org/Article" class="post-block" lang="zh-CN">
    <link itemprop="mainEntityOfPage" href="http://hdu_university.gitee.io/song311/2020/09/22/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="image" content="/song311/images/avatar.gif">
      <meta itemprop="name" content="asong">
      <meta itemprop="description" content="">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="Song's blog">
    </span>
      <header class="post-header">
        <h1 class="post-title" itemprop="name headline">
          设计模式
        </h1>

        <div class="post-meta">
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-calendar"></i>
              </span>
              <span class="post-meta-item-text">发表于</span>
              

              <time title="创建时间：2020-09-22 00:00:00 / 修改时间：09:12:14" itemprop="dateCreated datePublished" datetime="2020-09-22T00:00:00+08:00">2020-09-22</time>
            </span>
            <span class="post-meta-item">
              <span class="post-meta-item-icon">
                <i class="far fa-folder"></i>
              </span>
              <span class="post-meta-item-text">分类于</span>
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/song311/categories/Java/" itemprop="url" rel="index"><span itemprop="name">Java</span></a>
                </span>
            </span>

          

        </div>
      </header>

    
    
    
    <div class="post-body" itemprop="articleBody">

      
        <h2 id="1-工厂模式"><a href="#1-工厂模式" class="headerlink" title="1. 工厂模式"></a>1. 工厂模式</h2><ul>
<li>简单工厂模式</li>
<li>工厂方法模式</li>
<li>抽象工厂模式</li>
</ul>
<a id="more"></a>

<h3 id="简单工厂模式"><a href="#简单工厂模式" class="headerlink" title="简单工厂模式"></a>简单工厂模式</h3><p><strong>定义：</strong><br>　　定义<strong>一个</strong>工厂类，根据传入的参数不同返回不同的实例，被创建的实例具有共同的父类或接口。</p>
<p><strong>适用场景：</strong><br>　　其实由定义也大概能推测出其使用场景，首先由于只有一个工厂类，所以工厂类中创建的对象不能太多，否则工厂类的业务逻辑就太复杂了，其次由于工厂类封装了对象的创建过程，所以客户端应该不关心对象的创建。总结一下适用场景：<br>　　（1）需要创建的对象较少。<br>　　（2）客户端不关心对象的创建过程。<br>以上就是简单工厂模式简单工厂模式的适用场景，下面看一个具体的实例。</p>
<p><strong>实例：</strong><br>　　创建一个可以绘制不同形状的绘图工具，可以绘制圆形，正方形，三角形，每个图形都会有一个draw()方法用于绘图，不看代码先考虑一下如何通过该模式设计完成此功能。</p>
<p>　　由题可知圆形，正方形，三角形都属于一种图形，并且都具有draw方法，所以首先可以定义一个接口或者抽象类，作为这三个图像的公共父类，并在其中声明一个公共的draw方法。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面就是编写具体的图形，每种图形都实现Shape 接口<br>圆形</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">CircleShape</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">CircleShape</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(  <span class="string">&quot;CircleShape: created&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(  <span class="string">&quot;draw: CircleShape&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>正方形</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RectShape</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">RectShape</span><span class="params">()</span> </span>&#123;</span><br><span class="line">       System.out.println(  <span class="string">&quot;RectShape: created&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>&#123;</span><br><span class="line">       System.out.println(  <span class="string">&quot;draw: RectShape&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>三角形</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">TriangleShape</span> <span class="keyword">implements</span> <span class="title">Shape</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">TriangleShape</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(  <span class="string">&quot;TriangleShape: created&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">draw</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(  <span class="string">&quot;draw: TriangleShape&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>下面是工厂类的具体实现</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">ShapeFactory</span> </span>&#123;</span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">final</span> String TAG = <span class="string">&quot;ShapeFactory&quot;</span>;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Shape <span class="title">getShape</span><span class="params">(String type)</span> </span>&#123;</span><br><span class="line">        Shape shape = <span class="keyword">null</span>;</span><br><span class="line">        <span class="keyword">if</span> (type.equalsIgnoreCase(<span class="string">&quot;circle&quot;</span>)) &#123;</span><br><span class="line">            shape = <span class="keyword">new</span> CircleShape();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type.equalsIgnoreCase(<span class="string">&quot;rect&quot;</span>)) &#123;</span><br><span class="line">            shape = <span class="keyword">new</span> RectShape();</span><br><span class="line">        &#125; <span class="keyword">else</span> <span class="keyword">if</span> (type.equalsIgnoreCase(<span class="string">&quot;triangle&quot;</span>)) &#123;</span><br><span class="line">            shape = <span class="keyword">new</span> TriangleShape();</span><br><span class="line">        &#125;</span><br><span class="line">        <span class="keyword">return</span> shape;</span><br><span class="line">    &#125;</span><br><span class="line">  &#125;</span><br></pre></td></tr></table></figure>

<p>在这个工厂类中通过传入不同的type可以new不同的形状，返回结果为Shape 类型，这个就是简单工厂核心的地方了。</p>
<p>客户端使用</p>
<p>画圆形</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">Shape shape= ShapeFactory.getShape(<span class="string">&quot;circle&quot;</span>);</span><br><span class="line">shape.draw();</span><br></pre></td></tr></table></figure>







<h3 id="工厂方法模式"><a href="#工厂方法模式" class="headerlink" title="工厂方法模式"></a>工厂方法模式</h3><p>工厂方法模式是简单工厂的仅一步深化， 在工厂方法模式中，我们不再提供一个统一的工厂类来创建所有的对象，而是针对不同的对象提供不同的工厂。也就是说每个对象都有一个与之对应的工厂。</p>
<p><strong>定义：</strong><br>　　定义一个用于创建对象的接口，让子类决定将哪一个类实例化。工厂方法模式让一个类的实例化延迟到其子类。</p>
<p><strong>实例：</strong><br>　　现在需要设计一个这样的图片加载类，它具有多个图片加载器，用来加载jpg，png，gif格式的图片，每个加载器都有一个read（）方法，用于读取图片。下面我们完成这个图片加载类。</p>
<p>首先完成图片加载器的设计，编写一个加载器的公共接口。</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">Reader</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">read</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Reader 里面只有一个read（）方法，然后完成各个图片加载器的代码。</p>
<p>Jpg图片加载器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JpgReader</span> <span class="keyword">implements</span> <span class="title">Reader</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.print(<span class="string">&quot;read jpg&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Png图片加载器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PngReader</span> <span class="keyword">implements</span> <span class="title">Reader</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.print(<span class="string">&quot;read png&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Gif图片加载器</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GifReader</span> <span class="keyword">implements</span> <span class="title">Reader</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">read</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.print(<span class="string">&quot;read gif&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>现在我们按照定义所说定义一个抽象的工厂接口ReaderFactory</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">ReaderFactory</span> </span>&#123;</span><br><span class="line">    <span class="function">Reader <span class="title">getReader</span><span class="params">()</span></span>;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>里面有一个getReader（）方法返回我们的Reader 类，接下来我们把上面定义好的每个图片加载器都提供一个工厂类，这些工厂类实现了ReaderFactory 。</p>
<p>Jpg加载器工厂</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">JpgReaderFactory</span> <span class="keyword">implements</span> <span class="title">ReaderFactory</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Reader <span class="title">getReader</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> JpgReader();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Png加载器工厂</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">PngReaderFactory</span> <span class="keyword">implements</span> <span class="title">ReaderFactory</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Reader <span class="title">getReader</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> PngReader();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>Gif加载器工厂</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">GifReaderFactory</span> <span class="keyword">implements</span> <span class="title">ReaderFactory</span> </span>&#123;</span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Reader <span class="title">getReader</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        <span class="keyword">return</span> <span class="keyword">new</span> GifReader();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>在每个工厂类中我们都通过复写的getReader（）方法返回各自的图片加载器对象</p>
<p>客户端使用</p>
<p>读取Jpg</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ReaderFactory factory=<span class="keyword">new</span> JpgReaderFactory();</span><br><span class="line">Reader  reader=factory.getReader();</span><br><span class="line">reader.read();</span><br></pre></td></tr></table></figure>

<p>读取Png</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ReaderFactory factory=<span class="keyword">new</span> PngReaderFactory();</span><br><span class="line">Reader  reader=factory.getReader();</span><br><span class="line">reader.read();</span><br></pre></td></tr></table></figure>

<p>读取Gif</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">ReaderFactory factory=<span class="keyword">new</span> GifReaderFactory();</span><br><span class="line">Reader  reader=factory.getReader();</span><br><span class="line">reader.read();</span><br></pre></td></tr></table></figure>

<p>可以看到上面三段代码，分别读取了不同格式的图片，不同之处在于针对不同的图片格式声明了不同的工厂，进而创建了相应的图片加载器。</p>
<p>和简单工厂对比一下，最根本的区别在于，简单工厂只有一个统一的工厂类，而工厂方法是针对每个要创建的对象都会提供一个工厂类，这些工厂类都实现了一个工厂基类（本例中的ReaderFactory ）</p>
<p><strong>适用场景：</strong></p>
<p>　　（1）客户端不需要知道它所创建的对象的类。例子中我们不知道每个图片加载器具体叫什么名，只知道创建它的工厂名就完成了创建过程。<br>　　（2）客户端可以通过子类来指定创建对应的对象。<br>以上场景使用于采用工厂方法模式。</p>
<h2 id="2-单例模式"><a href="#2-单例模式" class="headerlink" title="2. 单例模式"></a>2. 单例模式</h2><p>看JUC2的彻底玩转单例模式</p>
<h2 id="3-代理模式"><a href="#3-代理模式" class="headerlink" title="3. 代理模式"></a>3. 代理模式</h2><ul>
<li>静态代理</li>
<li>动态代理</li>
</ul>
<h3 id="静态代理"><a href="#静态代理" class="headerlink" title="静态代理"></a>静态代理</h3><img src="/song311/D:/Typora/photo/image-20200908153800601.png" alt="image-20200908153800601" style="zoom:67%;">

<p>角色介绍:</p>
<ul>
<li>Subject — <strong>抽象主题类</strong>，定义了代理对象和真实对象的<strong>共同接口</strong>方法，既可以是接口也可以是抽象类。</li>
<li>RealSubject — <strong>真实主题类</strong>，该类可以被称为被委托类或被代理类，该类定义了代理对象所表示的<strong>真实对象</strong>，实现了Subject接口，而<strong>Client端通过代理类间接的调用的真实主题类中的方法</strong>，由其执行真正的业务逻辑。</li>
<li>ProxySubject — <strong>代理类</strong>，该类也被称为委托类或代理类，该类中<strong>持有一个真实主题类的引用</strong>，同样实现了Subject接口，在其实现的接口方法中调用真实主题类中相应的接口方法，以此起到<strong>代理的作用。</strong></li>
<li>Client — 客户端，使用代理。</li>
</ul>
<p>使用静态代理的基本步骤：</p>
<p>1、定义代理对象和真实对象的公共接口；</p>
<p>2、真实对象实现公共接口中的方法；</p>
<p>3、代理对象实现公共接口中的方法，并把方法的逻辑转发给真实对象。</p>
<p>我们通过小明买房的这个例子来讲解静态代理，小明想要在大城市租房，但是他平时很忙没有时间去看房，于是他就找到一个房产中介，把自己的租房意愿告诉房产中介，让房产中介来替自己解决租房问题，很明显房产中介就是代理人，小明就是被代理的人。</p>
<p>我们用静态代理来实现这个过程，首先定义一个租房步骤的公共接口：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//租房步骤公共接口，即Subject角色</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">IRoom</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">seekRoom</span><span class="params">()</span></span>;<span class="comment">//找房</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">watchRoom</span><span class="params">()</span></span>;<span class="comment">//看房</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">room</span><span class="params">()</span></span>;<span class="comment">//给钱租房</span></span><br><span class="line">    <span class="function"><span class="keyword">void</span> <span class="title">finish</span><span class="params">()</span></span>;<span class="comment">//完成租房</span></span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>4个步骤完成租房，很简单，然后我们定义具体的想要租房的人即小明：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//被代理人，想要租房的小明，即RealSubject角色</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">XiaoMing</span> <span class="keyword">implements</span> <span class="title">IRoom</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">seekRoom</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;找房&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">watchRoom</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;看房&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">room</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;给钱租房&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">finish</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        System.out.println(<span class="string">&quot;完成租房&quot;</span>);</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>该类实现了IRoom接口，实现了其中的具体逻辑，但是小明并不会自己去打租房，他<strong>委托</strong>房产中介去做，所以这里定义一个房产中介：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//代理人，房产中介，即ProxySubject角色</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">RoomAgency</span> <span class="keyword">implements</span> <span class="title">IRoom</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">private</span> IRoom mRoom;<span class="comment">//持有一个被代理人（小明）的引用</span></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">RoomAgency</span><span class="params">(IRoom room)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.mRoom = room;</span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">seekRoom</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mRoom.seekRoom();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">watchRoom</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mRoom.watchRoom();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">room</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mRoom.room();</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">void</span> <span class="title">finish</span><span class="params">()</span> </span>&#123;</span><br><span class="line">        mRoom.finish();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>


<p>在该类中会<strong>持有一个被代理人的引用</strong>，在这里指小明，可以看到房产中介所执行的方法的实质就是简单的调用被代理人中的方法，下面来看看Client中具体的执行关系：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//客户端，即Client角色</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span></span>&#123;</span><br><span class="line">        <span class="comment">//小明想租房</span></span><br><span class="line">        XiaoMing xiaoMing = <span class="keyword">new</span> XiaoMing();</span><br><span class="line">        <span class="comment">//找一个代理人，房产中介</span></span><br><span class="line">        RoomAgency roomAgency = <span class="keyword">new</span> RoomAgency(xiaoMing);</span><br><span class="line">        <span class="comment">//房产中介找房</span></span><br><span class="line">		roomAgency.watchRoom();</span><br><span class="line">        <span class="comment">//房产中介看房</span></span><br><span class="line">        roomAgency.seekRoom();</span><br><span class="line">        <span class="comment">//房产中介租房</span></span><br><span class="line">        roomAgency.room();</span><br><span class="line">        <span class="comment">//房产中介完成租房</span></span><br><span class="line">        roomAgency.finish();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>房产中介<strong>代理</strong>了小明的找房、看房、租房等过程，可以看到静态代理模式还是很简单，就是一种委托机制，真实对象将方法委托给代理对象，那么房产中介继续代理其他人可以吗? 可以的，比如XiaoHong也想租房，我们再定义一个XiaoHong实现IRoom接口，并在Client中给房产中介RoomAgency代理就行。</p>
<ul>
<li>缺点</li>
</ul>
<p>但是如果小明是想要买房而不是租房，这时房产中介还能满足小明的需求吗？很显然不能了，因为这个房产中介它只有替人租房的能力，没有替人买房的能力，这时就需要更换租房接口为买房接口，再定义一个专门买房的的房产中介，你会发现我每次更换接口，都需要更换代理类，这就是静态模式的缺点，<strong>只能为给定接口下的实现类做代理，如果接口不同就需要定义不同的代理类</strong>，随着系统的复杂度增加，就会很难维护这么多代理类和被代理类之间的关系，这时动态代理就应运而生，当需要频繁的更换接口，更换代理类时，采用动态代理是一个更好的选择，动态代理可以通过一个代理类来代理N多个被代理类，它在更换接口时，不需要重新定义代理类，因为动态代理<strong>不需要根据接口提前定义代理类，它把代理类的创建推迟到代码运行时来完成</strong>。</p>
<ul>
<li>与动态代理的区别</li>
</ul>
<p>我们先来复习一下class文件的加载，我们编写的.Java文件经过javac编译之后，会产生.class文件，这种.class文件是二进制文件，里面的内容是只有JVM能够识别，<strong>在代码运行之前</strong>，JVM会读取.class文件，解析.class文件内的信息，取出二进制数据，加载进内存中，从而生成对应的Class对象。</p>
<p>而静态代理和动态代理最主要的区别就是：静态代理在我们的<strong>代码运行之前</strong>，代理类的.class文件就已经存在，例如上述的RoomAgency.java，在经过javac编译之后，就会变成RoomAgency.class；而动态代理则与静态代理相反，在代码运行之前不存在代理类的.class文件，<strong>在代码运行时</strong>才动态的生成代理类。</p>
<h3 id="动态代理"><a href="#动态代理" class="headerlink" title="动态代理"></a>动态代理</h3><p><img src="/song311/D:/Typora/photo/image-20200908154951744.png" alt="image-20200908154951744"></p>
<p>与静态代理相比，多了一个InvocationHandler角色和一个Proxy角色，InvocationHandler是java提供的一个接口，我们需要定义一个类实现InvocationHandler接口，这里就叫DynamicProxy角色；Proxy是java提供用于动态生成ProxySubject的一个类，它需要ProxySubject继承。</p>
<p>我们看到DynamicProxy在ProxySubject和RealSubject之前起到了中间人的角色，ProxySubject会把事情委托给DynamicProxy来做，而DynamicProxy最终把事情委托给RealSubject来做，可以这样说：ProxySubject代理了DynamicProxy，而DynamicProxy代理了RealSubject，其中最重要的一点是<strong>ProxySubject是在代码运行时才动态生成</strong>的，这是和静态代理的最大区别。</p>
<h4 id="InvocationHandler和Proxy的作用"><a href="#InvocationHandler和Proxy的作用" class="headerlink" title="InvocationHandler和Proxy的作用"></a>InvocationHandler和Proxy的作用</h4><p>为了让我们更加容易的实现动态代理，java提供了动态代理接口InvocationHandler和动态代理类Proxy供我们使用，它们都在java.lang.reflect包中，可见动态代理和反射有不可逃脱的关系。</p>
<p>InvocationHandler接口 定义如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">interface</span> <span class="title">InvocationHandler</span> </span>&#123;</span><br><span class="line">  <span class="comment">/**</span></span><br><span class="line"><span class="comment">   * 这个方法的含义是：代理对象proxy要调用真实对象的method</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> proxy 代理对象</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> method 真实对象被调用的方法</span></span><br><span class="line"><span class="comment">   * <span class="doctag">@param</span> args 被调用的方法的参数</span></span><br><span class="line"><span class="comment">   */</span></span><br><span class="line">  <span class="function">Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args）<span class="keyword">throws</span> Throwable;</span></span></span><br><span class="line"><span class="function"><span class="params">&#125;</span></span></span><br><span class="line"><span class="function"><span class="params">复制代码</span></span></span><br></pre></td></tr></table></figure>

<p>InvocationHandler接口的作用就是在invoke方法中<strong>执行真实对象的方法</strong>，可以看到里面只有一个invoke方法，我们需要为真实对象定义一个实现了这个接口中的invoke方法的动态代理类，同时在创建这个动态代理类的实例的时候，我们还要在方法或构造中传入真实对象的引用，即InvocationHandler的实现类需要持有真实对象的引用，这样才能执行真实对象的方法。</p>
<p>Proxy类定义如下：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Proxy</span> <span class="keyword">implements</span> <span class="title">Serializable</span> </span>&#123;</span><br><span class="line">    </span><br><span class="line">    <span class="keyword">protected</span> InvocationHandler h;<span class="comment">//持有一个InvocationHandler类型的引用</span></span><br><span class="line"></span><br><span class="line">    <span class="function"><span class="keyword">protected</span> <span class="title">Proxy</span><span class="params">(InvocationHandler h)</span> </span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.h = h;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//根据指定的类加载器和接口来获取代理对象的Class对象</span></span><br><span class="line">    <span class="keyword">public</span> <span class="keyword">static</span> Class&lt;?&gt; getProxyClass(ClassLoader loader, Class... interfaces) <span class="keyword">throws</span> IllegalArgumentException &#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="comment">//根据指定的类加载器和接口生成代理对象</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> Object <span class="title">newProxyInstance</span><span class="params">(ClassLoader loader, Class&lt;?&gt;[] interfaces, InvocationHandler h)</span> <span class="keyword">throws</span> IllegalArgumentException </span>&#123;</span><br><span class="line">        <span class="comment">//...</span></span><br><span class="line">    &#125;</span><br><span class="line">    </span><br><span class="line">    <span class="comment">//...</span></span><br><span class="line">&#125;</span><br><span class="line"></span><br><span class="line">复制代码</span><br></pre></td></tr></table></figure>

<p>Proxy这个类的作用就是用来<strong>动态的创建一个代理对象</strong>，它内部会持有一个InvocationHandler引用，在构造中传入，它提供了许多的方法，但是我们常用的是 <strong>getProxyClass</strong>方法和<strong>newProxyInstance</strong>方法：</p>
<p><strong>getProxyClass</strong>（重点方法）：这个方法的作用是在运行时根据.class的结构生成一个代理Class二进制流，并通过传入的ClassLoader去把代理Class二进制流加载成一个代理Class对象，该代理Class对象继承Proxy并实现了传入的第二个参数对应的Interface列表。</p>
<p><strong>newProxyInstance</strong>(常使用的方法)： 这个方法的作用是在运行时根据代理Class对象生成代理对象实例，这个方法中会先调用了<strong>getProxyClass</strong>方法生成代理Class对象，在获取到代理Class对象后，根据第三个参数InvocationHandler引用通过反射创建代理对象实例，所以newProxyInstance最终的结果是生成一个代理对象实例，该代理对象会继承Proxy类并实现给定的接口列表，同时内部持有一个InvocationHandler引用。</p>
<h4 id="使用动态代理"><a href="#使用动态代理" class="headerlink" title="使用动态代理"></a>使用动态代理</h4><p>使用动态代理的基本步骤如下：</p>
<p>1、定义代理对象和真实对象的公共接口；（与静态代理步骤相同）</p>
<p>2、真实对象实现公共接口中的方法；（与静态代理步骤相同）</p>
<p>3、定义一个实现了InvocationHandler接口的动态代理类；</p>
<p>4、通过Proxy类的newProxyInstance方法创建代理对象，调用代理对象的方法。</p>
<p>和静态代理相比，少了的一个步骤是：代理对象实现公共接口的方法，因为前面讲过代理对象是代码运行时通过Proxy动态创建的，所以不需要提前编写代理对象的类</p>
<p>接着静态代理的小明买房的例子，下面分别讲解：</p>
<p>步骤3：我们需要定义一个动态代理类，它用于执行真实对象的方法：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment">//实现了InvocationHandler接口的动态代理类</span></span><br><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">DynamicProxy</span> <span class="keyword">implements</span> <span class="title">InvocationHandler</span> </span>&#123;</span><br><span class="line"></span><br><span class="line">    <span class="keyword">private</span> Object mObject;<span class="comment">//真实对象的引用</span></span><br><span class="line">    </span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="title">DynamicProxy</span><span class="params">(Object object)</span></span>&#123;</span><br><span class="line">        <span class="keyword">this</span>.mObject = object;</span><br><span class="line">    &#125;</span><br><span class="line"></span><br><span class="line">    <span class="meta">@Override</span></span><br><span class="line">    <span class="function"><span class="keyword">public</span> Object <span class="title">invoke</span><span class="params">(Object proxy, Method method, Object[] args)</span> <span class="keyword">throws</span> Throwable </span>&#123;</span><br><span class="line">        system.out.println(<span class="string">&quot;方法前调用&quot;</span>)  <span class="comment">//这里就实现了自定义的切面逻辑，这种原理就是AOP的原理</span></span><br><span class="line">        <span class="comment">//通过反射调用真实对象的方法</span></span><br><span class="line">        Object result = method.invoke(mObject, args);</span><br><span class="line">        system.out.println(<span class="string">&quot;方法后调用&quot;</span>)</span><br><span class="line">        <span class="keyword">return</span> result;</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br><span class="line"></span><br></pre></td></tr></table></figure>

<p>在该类中，我们声明了一个Object引用，该引用指向真实对象，真实对象在构造函数中传入，而在invoke方法中通过反射调用真实对象的具体方法，这里需要注意的是指向真实对象的引用类型最好定义为Objec类型而不是真实对象的具体类型如XiaoMing，这样做的好处是，当你要代理另外一个人时，例如xiaoHong，我在DynamicProxy的构造函数中只需要传入xiaoHong引用而不用更改DynamicProxy的类结构，这样一个DynamicProxy就可以代理很多人。</p>
<p>接着步骤4：通过Proxy类newProxyInstance方法创建代理对象，调用代理对象的方法，下面是Client端逻辑:</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">public</span> <span class="class"><span class="keyword">class</span> <span class="title">Client</span> </span>&#123;</span><br><span class="line">    <span class="function"><span class="keyword">public</span> <span class="keyword">static</span> <span class="keyword">void</span> <span class="title">main</span><span class="params">(String[] args)</span> </span>&#123;</span><br><span class="line">        <span class="comment">//构造一个小明</span></span><br><span class="line">        IRoom xiaoMing = <span class="keyword">new</span> XiaoMing();</span><br><span class="line">        <span class="comment">//构造一个动态代理</span></span><br><span class="line">        InvocationHandler dynamicProxy = <span class="keyword">new</span> DynamicProxy(xiaoMing);</span><br><span class="line">        <span class="comment">//获取被代理类小明的ClassLoader</span></span><br><span class="line">        ClassLoader classLoader = xiaoMing.getClass().getClassLoader();</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//1、通过Proxy类的newProxyInstance方法动态构造一个代理人房产中介</span></span><br><span class="line">        IRoom roomAgency = (IRoom) Proxy.newProxyInstance(classLoader, <span class="keyword">new</span> Class[]&#123;IRoom.class&#125;, dynamicProxy);</span><br><span class="line">        </span><br><span class="line">        <span class="comment">//调用代理对象的方法</span></span><br><span class="line">        </span><br><span class="line">        <span class="comment">//房产中介找房</span></span><br><span class="line">        roomAgency.watchRoom();</span><br><span class="line">        <span class="comment">//房产中介看房</span></span><br><span class="line">        roomAgency.seekRoom();</span><br><span class="line">        <span class="comment">//房产中介租房</span></span><br><span class="line">        roomAgency.room();</span><br><span class="line">        <span class="comment">//房产中介完成租房</span></span><br><span class="line">        roomAgency.finish();</span><br><span class="line">    &#125;</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>

<p>运行结果和前面的静态代理一致，就不再贴出，在介绍Proxy时讲过，Proxy的newProxyInstance方法会根据传入的类加载器动态生成代理对象实例，生成的代理对象会继承Proxy类并实现传入的接口列表，这里的类加载器是小明的ClassLoader，即真实对象的类加载器，而<strong>接口列表</strong>则是IRoom，传入的IRoom的Class对象，除了这个两个参数，还传入了动态代理类InvocationHandler实例，这样Proxy类在创建代理对象的实例时就会把这个InvocationHandler引用传给代理对象，接下来<strong>当我们调用代理对象的方法时，这个方法的处理逻辑就会委托给InvocationHandler实例的invoke方法执行，invoke方法中就会通过反射调用我们真实对象的方法</strong>。</p>

    </div>
	<div>
		
		

		
	</div>



    
    
    

      <footer class="post-footer">
          <div class="post-tags">
              <a href="/song311/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" rel="tag"># 设计模式</a>
          </div>

        


        
    <div class="post-nav">
      <div class="post-nav-item"></div>
      <div class="post-nav-item">
    <a href="/song311/2020/09/22/2020-09-22-test3/" rel="next" title="test3">
      test3 <i class="fa fa-chevron-right"></i>
    </a></div>
    </div>
      </footer>
    
  </article>
  
  
  



          </div>
          

<script>
  window.addEventListener('tabs:register', () => {
    let { activeClass } = CONFIG.comments;
    if (CONFIG.comments.storage) {
      activeClass = localStorage.getItem('comments_active') || activeClass;
    }
    if (activeClass) {
      let activeTab = document.querySelector(`a[href="#comment-${activeClass}"]`);
      if (activeTab) {
        activeTab.click();
      }
    }
  });
  if (CONFIG.comments.storage) {
    window.addEventListener('tabs:click', event => {
      if (!event.target.matches('.tabs-comment .tab-content .tab-pane')) return;
      let commentClass = event.target.classList[1];
      localStorage.setItem('comments_active', commentClass);
    });
  }
</script>

        </div>
          
  
  <div class="toggle sidebar-toggle">
    <span class="toggle-line toggle-line-first"></span>
    <span class="toggle-line toggle-line-middle"></span>
    <span class="toggle-line toggle-line-last"></span>
  </div>

  <aside class="sidebar">
    <div class="sidebar-inner">

      <ul class="sidebar-nav motion-element">
        <li class="sidebar-nav-toc">
          文章目录
        </li>
        <li class="sidebar-nav-overview">
          站点概览
        </li>
      </ul>

      <!--noindex-->
      <div class="post-toc-wrap sidebar-panel">
          <div class="post-toc motion-element"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#1-%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F"><span class="nav-number">1.</span> <span class="nav-text">1. 工厂模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E7%AE%80%E5%8D%95%E5%B7%A5%E5%8E%82%E6%A8%A1%E5%BC%8F"><span class="nav-number">1.1.</span> <span class="nav-text">简单工厂模式</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%B7%A5%E5%8E%82%E6%96%B9%E6%B3%95%E6%A8%A1%E5%BC%8F"><span class="nav-number">1.2.</span> <span class="nav-text">工厂方法模式</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#2-%E5%8D%95%E4%BE%8B%E6%A8%A1%E5%BC%8F"><span class="nav-number">2.</span> <span class="nav-text">2. 单例模式</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#3-%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F"><span class="nav-number">3.</span> <span class="nav-text">3. 代理模式</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#%E9%9D%99%E6%80%81%E4%BB%A3%E7%90%86"><span class="nav-number">3.1.</span> <span class="nav-text">静态代理</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="nav-number">3.2.</span> <span class="nav-text">动态代理</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#InvocationHandler%E5%92%8CProxy%E7%9A%84%E4%BD%9C%E7%94%A8"><span class="nav-number">3.2.1.</span> <span class="nav-text">InvocationHandler和Proxy的作用</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#%E4%BD%BF%E7%94%A8%E5%8A%A8%E6%80%81%E4%BB%A3%E7%90%86"><span class="nav-number">3.2.2.</span> <span class="nav-text">使用动态代理</span></a></li></ol></li></ol></li></ol></div>
      </div>
      <!--/noindex-->

      <div class="site-overview-wrap sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
    <img class="site-author-image" itemprop="image" alt="asong"
      src="/song311/images/avatar.gif">
  <p class="site-author-name" itemprop="name">asong</p>
  <div class="site-description" itemprop="description"></div>
</div>
<div class="site-state-wrap motion-element">
  <nav class="site-state">
      <div class="site-state-item site-state-posts">
          <a href="/song311/archives/">
        
          <span class="site-state-item-count">6</span>
          <span class="site-state-item-name">日志</span>
        </a>
      </div>
      <div class="site-state-item site-state-categories">
            <a href="/song311/categories/">
          
        <span class="site-state-item-count">5</span>
        <span class="site-state-item-name">分类</span></a>
      </div>
      <div class="site-state-item site-state-tags">
            <a href="/song311/tags/">
          
        <span class="site-state-item-count">5</span>
        <span class="site-state-item-name">标签</span></a>
      </div>
  </nav>
</div>
  <div class="links-of-author motion-element">
      <span class="links-of-author-item">
        <a href="mailto:asong0311@163.com" title="E-Mail → mailto:asong0311@163.com" rel="noopener" target="_blank"><i class="fa fa-envelope fa-fw"></i>E-Mail</a>
      </span>
  </div>



      </div>
        <div class="back-to-top motion-element">
          <i class="fa fa-arrow-up"></i>
          <span>0%</span>
        </div>
	
		<script type="text/javascript" charset="utf-8" src="/js/tagcloud.js"></script>
		<script type="text/javascript" charset="utf-8" src="/js/tagcanvas.js"></script>
		<div class="widget-wrap">
			<h3 class="widget-title">Tag Cloud</h3>
			<div id="myCanvasContainer" class="widget tagcloud">
				<canvas width="250" height="250" id="resCanvas" style="width=100%">
					<ul class="tag-list" itemprop="keywords"><li class="tag-list-item"><a class="tag-list-link" href="/song311/tags/telnet/" rel="tag">telnet</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/song311/tags/test/" rel="tag">test</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/song311/tags/%E8%AE%BE%E8%AE%A1%E6%A8%A1%E5%BC%8F/" rel="tag">设计模式</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/song311/tags/%E9%93%BE%E8%A1%A8/" rel="tag">链表</a><span class="tag-list-count">1</span></li><li class="tag-list-item"><a class="tag-list-link" href="/song311/tags/%E9%94%99%E8%AF%AF/" rel="tag">错误</a><span class="tag-list-count">2</span></li></ul>
				</canvas>
			</div>
		</div>
	

    </div>
  </aside>
  <div id="sidebar-dimmer"></div>


      </div>
    </main>

    <footer class="footer">
      <div class="footer-inner">
        

        <script async src="https://busuanzi.ibruce.info/busuanzi/2.3/busuanzi.pure.mini.js"></script>

<span id="busuanzi_container_site_uv">
  访客数:<span id="busuanzi_value_site_uv"></span>人次
</span>


  <!--<div class="powered-by">由 <a class="theme-link" target="_blank" href="https://hexo.io">Hexo</a> 强力驱动</div>-->







<span id="busuanzi_container_site_pv">
   总访问量:<span id="busuanzi_value_site_pv"></span>次
</span>





<div class="theme-info">
  <div class="powered-by"></div>
  <span class="post-count">博客全站共5.9k字</span>
</div>

<div class="copyright">
  
  &copy; 
  <span itemprop="copyrightYear">2020</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">asong</span>
</div>
  <!--<div class="powered-by">由 <a href="https://hexo.io/" class="theme-link" rel="noopener" target="_blank">Hexo</a> & <a href="https://theme-next.org/" class="theme-link" rel="noopener" target="_blank">NexT.Gemini</a> 强力驱动
  </div>-->

        








      </div>
    </footer>
  </div>

  
  <script src="/song311/lib/anime.min.js"></script>
  <script src="/song311/lib/velocity/velocity.min.js"></script>
  <script src="/song311/lib/velocity/velocity.ui.min.js"></script>

<script src="/song311/js/utils.js"></script>

<script src="/song311/js/motion.js"></script>


<script src="/song311/js/schemes/pisces.js"></script>


<script src="/song311/js/next-boot.js"></script>




  




  
<script src="/song311/js/local-search.js"></script>













  

  

</body>
</html>
